package com.seanzx.lexical;

import com.seanzx.constant.SymbolTable;

import java.util.ArrayList;
import java.util.List;

public class LexicalAnalyzer {
    public static final String[] SEPARATORS = {" "};
    public static final String[] TRANS_FLAG = {"`", "'", "\""};
    public static final String[] OPERATORS = SymbolTable.operators();

    public static List<Token> analysis(char[] sql) {
        char recognizerChar = '\000';
        List<Token> tokens = new ArrayList<>();
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < sql.length; i++) {
            char character = sql[i];
            if (recognizerChar != '\000') {
                if (character == recognizerChar) {
                    recognizerChar = '\000';
                    Token token = new Token();
                    token.setType(TokenType.VALUE_IN_TRANS);
                    token.setValue(builder.toString());
                    tokens.add(token);
                    builder = new StringBuilder();
                    continue;
                }
                builder.append(character);
                continue;
            }
            String symbol;
            if (find(sql, i, SEPARATORS) != null) {
                if (builder.toString().trim().length() > 0) {
                    addToken(tokens, builder.toString());

                    builder = new StringBuilder();
                }

            } else if ((symbol = find(sql, i, TRANS_FLAG)) != null) {
                recognizerChar = symbol.charAt(0);

            } else if ((symbol = find(sql, i, OPERATORS)) != null) {
                if (builder.toString().trim().length() > 0) {
                    addToken(tokens, builder.toString());
                }
                addToken(tokens,  symbol);

                builder = new StringBuilder();

            } else {
                builder.append(character);
            }
        }
        if (builder.toString().trim().length() > 0) {
            Token token = new Token();
            token.setType(SymbolTable.get(builder.toString()));
            token.setValue(builder.toString());
            tokens.add(token);
        }
        return tokens;
    }

    private static String find(char[] sql, int startIndex, String[] symbols) {
        for (String symbol : symbols) {
            for (int j = 0; j < sql.length; j++) {
                char character = sql[startIndex + j];
                if (j >= symbol.length()) {
                    return symbol;
                }
                if (symbol.charAt(j) != character) {
                    break;
                }
            }
        }
        return null;
    }

    private static void addToken(List<Token> tokens, String s) {
        Token token;
        token = new Token();
        token.setType(SymbolTable.get(s.toUpperCase()));
        if (!token.getType().equals(TokenType.VALUE)) {
            token.setValue(s.toUpperCase());
        } else {
            token.setValue(s);
        }
        tokens.add(token);
    }

    public static void main(String[] args) {
        List<Token> analysis = analysis("SELECT * FROM information_schema.TABLES WHERE id > 6 AND TABLE_NAME LIKE 'COLUMN%' OR id < 3".toCharArray());
        for (Token token : analysis) {
            System.out.println(token.getType() + ":" + token.getValue());
        }
    }
}
